using System.Collections.Generic;
using System.Text;
using System;
namespace Framework
{
    public class BundleInfo
    {
        public string Path;
        public int Hash0;
        public int Hash1;
        public int Size;
        public int Encrypt;
        public ushort[] DirectDependencies;
        public BundleInfo Clone()
        {
            var info = new BundleInfo();
            info.Path = Path;
            info.Hash0 = Hash0;
            info.Hash1 = Hash1;
            info.Size = Size;
            info.Encrypt = Encrypt;
            info.DirectDependencies = new ushort[DirectDependencies.Length];
            for (var i = 0; i < DirectDependencies.Length; i++)
            {
                info.DirectDependencies[i] = DirectDependencies[i];
            }
            return info;
        }
        public bool Equals(BundleInfo other)
        {
            return Hash0 == other.Hash0 && Hash1 == other.Hash1;
        }
    }
    public class AssetsInfo
    {
        public string Version;
        public string BundleExtension;
        public string BuildTime;
        public string UnityVersion;
        public string BuildTarget;
        public int AssetCount;
        public string UserData;
        public bool AppendHashToAssetBundleName;
        public BundleInfo[] Bundles;

        public void GetDirectDependencies(BundleInfo value, List<string> target)
        {
            var len = value.DirectDependencies.Length;
            while (len-- > 0)
            {
                var id = value.DirectDependencies[len];
                target.Add(Bundles[id].Path);
            }
        }
        public void GetAllDependencies(BundleInfo value, List<string> target)
        {
            var len = value.DirectDependencies.Length;
            while (len-- > 0)
            {
                var id = value.DirectDependencies[len];
                var t = Bundles[id];
                if (target.Contains(t.Path))
                {
                    continue;
                }
                target.Add(t.Path);
                GetAllDependencies(t, target);
            }
        }
        public static byte[] EncodeToBytes(AssetsInfo value)
        {
            var stringTable = new ByteArray(10240);
            Dictionary<string, short> tableMap = new(StringComparer.Ordinal);
            var bytes = new ByteArray(10240);
            bytes.WriteShortString(value.Version);
            bytes.WriteShortString(value.BundleExtension);
            bytes.WriteShortString(value.BuildTime);
            bytes.WriteShortString(value.UnityVersion);
            bytes.WriteShortString(value.BuildTarget);
            bytes.WriteInt(value.AssetCount);
            bytes.WriteString(value.UserData);
            bytes.WriteBool(value.AppendHashToAssetBundleName);
            bytes.WriteInt(value.Bundles.Length);
            var len = value.Bundles.Length;
            for (int i = 0; i < len; i++)
            {
                var info = value.Bundles[i];
                var name = info.Path;
                //assets/
                name = name.Substring(7);

                var pname = name.Split('/');
                var plen = ((byte)pname.Length);
                bytes.WriteByte(plen);
                for (int j = 0; j < plen; j++)
                {
                    var p = pname[j];
                    if (!tableMap.TryGetValue(p, out short index))
                    {
                        index = ((short)tableMap.Count);
                        tableMap.Add(p, index);
                        stringTable.WriteShortString(p);
                    }
                    bytes.WriteShort(index);
                }
                bytes.WriteInt(info.Hash0);
                bytes.WriteInt(info.Hash1);
                bytes.WriteInt(info.Size);
                bytes.WriteBool(info.Encrypt == 1);
                bytes.WriteByte(((byte)info.DirectDependencies.Length));
                for (var j = 0; j < info.DirectDependencies.Length; j++)
                {
                    bytes.WriteUShort(((ushort)info.DirectDependencies[j]));
                }
            }
            var allBytes = new ByteArray(10240);
            allBytes.WriteShort(((short)tableMap.Count));
            len = stringTable.Position;
            allBytes.Write<byte>(stringTable.Buffer.Buffer, 0, stringTable.Position);
            allBytes.Write<byte>(bytes.Buffer.Buffer, 0, bytes.Position);
            var data = new byte[allBytes.Position];
            allBytes.CopyTo(data);
            return data;
        }
        public static AssetsInfo Decode(byte[] data)
        {
            var info = new AssetsInfo();
            var bytes = new ByteArray(data);
            var tableLen = bytes.ReadShort();
            var stringTable = new string[tableLen];
            for (int i = 0; i < tableLen; i++)
            {
                stringTable[i] = bytes.ReadShortString();
            }
            info.Version = bytes.ReadShortString();
            info.BundleExtension = bytes.ReadShortString();
            info.BuildTime = bytes.ReadShortString();
            info.UnityVersion = bytes.ReadShortString();
            info.BuildTarget = bytes.ReadShortString();
            info.AssetCount = bytes.ReadInt();
            info.UserData = bytes.ReadString();
            info.AppendHashToAssetBundleName = bytes.ReadBool();
            var len = bytes.ReadInt();
            if (len > 100000)
            {
                len = 0;
            }
            info.Bundles = new BundleInfo[len];
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < len; i++)
            {
                var bundle = new BundleInfo();
                info.Bundles[i] = bundle;
                var plen = bytes.ReadByte();
                sb.Clear();
                for (var j = 0; j < plen; j++)
                {
                    var id = bytes.ReadShort();
                    if (j > 0)
                    {
                        sb.Append("/");
                    }
                    sb.Append(stringTable[id]);
                }
                bundle.Path = "assets/" + sb.ToString() + info.BundleExtension;
                bundle.Hash0 = bytes.ReadInt();
                bundle.Hash1 = bytes.ReadInt();
                bundle.Size = bytes.ReadInt();
                bundle.Encrypt = bytes.ReadBool() ? 1 : 0;
                var dlen = bytes.ReadByte();
                bundle.DirectDependencies = new ushort[dlen];
                for (var j = 0; j < dlen; j++)
                {
                    bundle.DirectDependencies[j] = bytes.ReadUshort();
                }
            }
            return info;
        }
        public AssetsInfo Clone()
        {
            var info = new AssetsInfo
            {
                Version = Version,
                BundleExtension = BundleExtension,
                BuildTime = BuildTime,
                UnityVersion = UnityVersion,
                BuildTarget = BuildTarget,
                AssetCount = AssetCount,
                UserData = UserData,
                AppendHashToAssetBundleName = AppendHashToAssetBundleName
            };
            var list = new BundleInfo[Bundles.Length];
            var len = Bundles.Length;
            for (int i = 0; i < len; i++)
            {
                list[i] = Bundles[i].Clone();
            }
            info.Bundles = list;
            return info;
        }
    }
}